package satellite.nav.post;

import satellite.nav.utils.GpsTime;
import satellite.nav.utils.GpsTimeUtils;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Program : satellite-nav
 * @ClassName : ReadObsData
 * @Description : 读取Rinex格式中的O文件内容
 * @Date: 2021-12-15 13:58
 * @Version : 1.0
 */
public class ReadObsData {

    //测站数据
    private StationData station_data;

    //测历元数据集合
    private Map<GpsTime, List<ObsEpoch>> obsEpochMap;


    public ReadObsData(String FilePath){
        station_data=new StationData();
        obsEpochMap=new HashMap<>();
        readObsFile(FilePath);
    }

    private void readObsFile(String path){
        FileReader fr=null;
        BufferedReader br = null;
        //观测类型
        List<String>type_obs=new ArrayList<>();

        try{
            fr=new FileReader(path);
            br=new BufferedReader(fr);
            String str="";
            //读取头文件数据
            while((str=br.readLine())!=null){
                switch (str.substring(60).trim()){
                    //获取测站近似坐标
                    case "APPROX POSITION XYZ":
                        String posStr=str.substring(0,60).trim();
                        String[]PosArrays=posStr.split(" ");
                        List<String>Pos=new ArrayList<>();
                        for(int i=0;i<PosArrays.length;i++){
                            if(!PosArrays[i].equals("")){
                                Pos.add(PosArrays[i]);
                            }
                        }
                        station_data.setX_Pos(Double.valueOf(Pos.get(0).trim()));
                        station_data.setY_Pos(Double.valueOf(Pos.get(1).trim()));
                        station_data.setZ_Pos(Double.valueOf(Pos.get(2).trim()));
                        continue;
                        //获取观测类型
                    case "# / TYPES OF OBSERV":
                        String typeObs=str.substring(1,60).trim();
                        String[]typeObs_arr=typeObs.split("    ");
                        if(typeObs_arr.length!=0){
                            for(int i=1;i<typeObs_arr.length;i++){
                                type_obs.add(typeObs_arr[i]);
                                switch (typeObs_arr[i]){
                                    case "L1":   station_data.setL1(true);continue;
                                    case "L2":   station_data.setL2(true);continue;
                                    case "C1":   station_data.setC1(true);continue;
                                    case "P1":   station_data.setP1(true);continue;
                                    case "P2":   station_data.setP2(true);continue;
                                    case "S1":   station_data.setS1(true);continue;
                                    case "S2":   station_data.setS2(true);continue;
                                }
                            }
                            //如果观测类型数目大于9，则继续读下一行数据
                            if(Integer.valueOf(typeObs_arr[0])>9){
                                str=br.readLine().substring(1,60).trim();
                                String[]typeObs_arr_add=str.split("    ");
                                if(typeObs_arr_add.length!=0){
                                    for(int i=0;i<typeObs_arr_add.length;i++){
                                        type_obs.add(typeObs_arr_add[i]);
                                    }
                                }
                            }
                        }
                        continue;
                        //头文件结束符
                    case "END OF HEADER":
                        break;
                    default:
                        continue;
                }
                break;
            }
            //头文件数据结束

            //读取观测值数据
            while ((str=br.readLine())!=null){
                //历元开始的标识
                if(str.contains("G") || str.contains("R")){
                    //获取观测历元时刻
                    int year=Integer.valueOf(str.substring(1,3).trim());
                    int month=Integer.valueOf(str.substring(4,6).trim());
                    int day=Integer.valueOf(str.substring(7,9).trim());
                    int hour=Integer.valueOf(str.substring(10,12).trim());
                    int minute=Integer.valueOf(str.substring(13,15).trim());
                    int sec=Integer.valueOf(str.substring(16,18).trim());

                    /**UTC时--->GPS时*/
                    GpsTime obs_t= GpsTimeUtils.utcToGpsTime(year,month,day,hour,minute,sec);
                    /**该历元下的观测卫星的数量*/
                    int sv_num=Integer.valueOf(str.substring(30,32));
                    StringBuilder stringBuilder=new StringBuilder();
                    String sv_prn_str=str.substring(32);
                    /**超过12颗卫星则继续读下一行*/
                    if(sv_num>12){
                        sv_prn_str=sv_prn_str.substring(0,36);
                        String sv_prn_str_add=br.readLine().trim();
                        stringBuilder.append(sv_prn_str).append(sv_prn_str_add);
                        sv_prn_str=stringBuilder.toString();
                    }
                    else {
                        sv_prn_str=sv_prn_str.substring(32,32+sv_num*3);
                    }
                    /**读取该历元下的所有卫星观测数据*/
                    List<ObsEpoch> ObsEpochList=new ArrayList<>();
                    ObsEpoch obsEpoch; /*历元观测数据*/
                    for(int i=0;i<sv_num;i++){
                        obsEpoch=new ObsEpoch();
                        obsEpoch.setObs_t(obs_t); /*设置观测历元(gpst)*/
                        String prn=sv_prn_str.substring(i*3,i*3+3);
                        obsEpoch.setPrn(prn); /*设置改历元下卫星的PRN*/
                        str=br.readLine();
                        int type_obs_num=type_obs.size();  /**观测类型的数量*/
                        List<String>value=new ArrayList<>();
                        if(type_obs_num>5){
                            setValue(str,5,value);
                            for(int j=0;j<5;j++){
                                String type=type_obs.get(j);
                                String value_input=value.get(j);
                                setMeasureValue(type,obsEpoch,value_input);
                            }
                            /**继续读下一行的观测值数据*/
                            str=br.readLine();
                            int residue_num=type_obs_num-5;
                            setValue(str,residue_num,value);
                            for(int u=5;u<type_obs_num;u++){
                                String type=type_obs.get(u);
                                String value_input=value.get(u);
                                setMeasureValue(type,obsEpoch,value_input);
                            }

                        } else {
                            setValue(str,type_obs_num,value);
                            for(int u=0;u<type_obs_num;u++){
                                String type=type_obs.get(u);
                                String value_input=value.get(u);
                                setMeasureValue(type,obsEpoch,value_input);
                            }
                        }
                        ObsEpochList.add(obsEpoch);
                    }
                    obsEpochMap.put(obs_t,ObsEpochList);
                }
            }
            //观测值数据读取结束

        } catch (IOException e) {
            e.printStackTrace();
        }  finally {
            //关闭文件输入流
            try {
                if(br!=null) {
                    br.close();
                }
                if(fr!=null) {
                    fr.close();
                }
            }catch(IOException e) {
                e.printStackTrace();
            }
        }
    }

    //返回读取的测站数据
    public StationData getStation_data() {
        return station_data;
    }
    //返回读取的观测历元数据
    public Map<GpsTime, List<ObsEpoch>> getObsEpochMap() {
        return obsEpochMap;
    }

    //将获取的观测类型数据存储至观测历元类中,缺失则为“0.0”
    private void setMeasureValue(String type,ObsEpoch obsEpoch,String value){
        double v;
        if(value.equals("")){
            v=0.0;
        }
        else {
            v=Double.valueOf(value);
        }
        switch (type){
            case "L1":obsEpoch.setL1(v);break;
            case "L2":obsEpoch.setL2(v);break;
            case "C1":obsEpoch.setC1(v);break;
            case "P1":obsEpoch.setP1(v);break;
            case "P2":obsEpoch.setP2(v);break;
            case "S1":obsEpoch.setS1(v);break;
            case "S2":obsEpoch.setS2(v);break;
            default:
                break;

        }
    }

    //根据观测类型，获取每行的观测数据，缺失则为空
    private void setValue(String str,int type,List<String> value) {
        int length=str.length();
        int index=0;
        if(length>(type-1)*16){
            if (length<=16){
                value.add(str.substring(0,14).trim());

            }
            else if (length>16 && length<=32){
                value.add(str.substring(0,16).substring(0,14).trim());
                value.add(str.substring(16).substring(0,14).trim());
            }
            else if(length>32 && length<=48){
                value.add(str.substring(0,16).substring(0,14).trim());
                value.add(str.substring(16,32).substring(0,14).trim());
                value.add(str.substring(32).trim());
            }
            else if(length>48 && length<=64){
                value.add(str.substring(0,16).substring(0,14).trim());
                value.add(str.substring(16,32).substring(0,14).trim());
                value.add(str.substring(32,48).substring(0,14).trim());
                value.add(str.substring(48).substring(0,14).trim());
            }

            else if(length>64){
                value.add(str.substring(0,16).substring(0,14).trim());
                value.add(str.substring(16,32).substring(0,14).trim());
                value.add(str.substring(32,48).substring(0,14).trim());
                value.add(str.substring(48,64).substring(0,14).trim());
                value.add(str.substring(64).substring(0,14).trim());
            }

        }
        else {
            if(length<=16){
                if (length == 0) {
                    index=0;
                    for(int i=0;i<type-index;i++){
                        value.add("");
                    }
                }
                else{
                    index=1;
                    value.add(str.substring(0,14).trim());
                    for(int i=0;i<type-index;i++){
                        value.add("");
                    }
                }

            }
            else if(length>16 && length<=32){
                index=2;
                value.add(str.substring(0,16).substring(0,14).trim());
                value.add(str.substring(16).substring(0,14).trim());
                for(int i=0;i<type-index;i++){
                    value.add("");
                }
            }
            else if(length>32 && length<=48){
                index=3;
                value.add(str.substring(0,16).substring(0,14).trim());
                value.add(str.substring(16,32).substring(0,14).trim());
                value.add(str.substring(32).trim());
                for(int i=0;i<type-index;i++){
                    value.add("");
                }
            }
            else if(length>48 && length<=64){
                index=4;
                value.add(str.substring(0,16).substring(0,14).trim());
                value.add(str.substring(16,32).substring(0,14).trim());
                value.add(str.substring(32,48).substring(0,14).trim());
                value.add(str.substring(48).substring(0,14).trim());
                for(int i=0;i<type-index;i++){
                    value.add("");
                }
            }
        }
    }

}
